﻿// ***********************************************************************
// Provided for Informational Purposes Only
//
// Apache 2.0 License
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 
// PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.
// ***********************************************************************
// Assembly  : ContractMeow.Api.WinRT
// File      : ResponseErrorHandler.cs
//
// ***********************************************************************

using ContractMeow.Api.Dtos;
using ContractMeow.Api.Exceptions;
using ContractMeow.WinRT.Serialization;
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace ContractMeow.Api
{
	/// <summary>
	/// Class ResponseErrorHandler
	/// </summary>
	public class ResponseErrorHandler : IResponseErrorHandler
	{
		private readonly IDeserializer _Deserializer;
		private readonly IErrorToExceptionTranslator _ErrorToExceptionTranslator;

		/// <summary>
		/// Initializes a new instance of the <see cref="ResponseErrorHandler" /> class.
		/// </summary>
		/// <param name="deserializer">The deserializer.</param>
		/// <param name="errorToExceptionTranslator">The error to exception translator.</param>
		public ResponseErrorHandler(IDeserializer deserializer, IErrorToExceptionTranslator errorToExceptionTranslator)
		{
			_Deserializer = deserializer;
			_ErrorToExceptionTranslator = errorToExceptionTranslator;
		}

		/// <summary>
		/// Returns exceptions for known error types so they can be handled properly, if desired.
		/// </summary>
		/// <param name="response">The http response</param>
		/// <returns>Task{Exception}.</returns>
		/// <exception cref="ServerErrorException"></exception>
		/// <exception cref="ConnectionFailureException"></exception>
		public async Task<Exception> HandleAsync(HttpResponseMessage response)
		{
			//Currently the server will return html in this case, so there's nothing useful to do.
			if (response.StatusCode == HttpStatusCode.InternalServerError)
				return new ServerErrorException();

			//No valuable information in the content.
			if (response.StatusCode == HttpStatusCode.GatewayTimeout
				|| response.StatusCode == HttpStatusCode.ServiceUnavailable
				|| response.StatusCode == HttpStatusCode.RequestTimeout)
				return new ConnectionFailureException();
			if (response.StatusCode == HttpStatusCode.Unauthorized)
			{
				var msg = await response.Content.ReadAsStringAsync();
				if (msg.Contains("{"))
				{
					msg = msg.Replace("{", string.Empty).Replace("}", string.Empty);
				}
				return new UnauthorizedException(msg, response.StatusCode);
			}
			if (response.StatusCode == HttpStatusCode.Forbidden)
			{
				var msg = await response.Content.ReadAsStringAsync();
				return new ForbiddenException(msg, response.StatusCode);
			}

			Byte[] errorResponse = await response.Content.ReadAsByteArrayAsync();

			if (errorResponse == null || errorResponse.Length <= 0)
				return null;

			Error err;
			try
			{
				err = _Deserializer.Deserialize<Error>(errorResponse);

				if (err == null)
					return null;

				if (!err.IsValid())
				{
					var msg = await response.Content.ReadAsStringAsync();
					var deserializationError = new Exception(msg);
					return deserializationError;
				}

			}
			catch (Exception ex)
			{
				return ex;
			}

			var exception = _ErrorToExceptionTranslator.Translate(response.StatusCode, err);

			return exception;
		}
	}
}